package com.dao.base;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.util.Assert;

/**
 * @author geliyang
 *
 * @param <T>
 * @param <ID>
 */
public class BaseRepositoryImpl<T, ID extends Serializable> extends SimpleJpaRepository<T, ID> implements BaseRepository<T, ID> {

	@PersistenceContext
	private EntityManager entityManager;

	private Class<T> entityClass;

	public BaseRepositoryImpl(Class<T> domainClass, EntityManager entityManager) {
		super(domainClass, entityManager);
		this.entityManager = entityManager;
		this.entityClass = domainClass;
	}

	@SuppressWarnings("unchecked")
	@Override
	public Page<T> sqlQuery(String queryString, String countSql, Map<String, ?> values, Pageable pageable) {

		Assert.hasText(queryString, "queryString不能为空");

		Query query = entityManager.createNativeQuery(queryString, this.entityClass);
		Query countQuery = entityManager.createNativeQuery(countSql);

		//给条件赋值
		if (values != null && !values.isEmpty()) {
			for (Map.Entry<String, ?> entry : values.entrySet()) {
				query.setParameter(entry.getKey(), entry.getValue());
				countQuery.setParameter(entry.getKey(), entry.getValue());
			}
		}

		if (pageable.getPageNumber() >= 0 && pageable.getPageSize() >= 0) {
			query.setFirstResult(pageable.getPageNumber()*pageable.getPageSize());
			query.setMaxResults(pageable.getPageSize());
		}

		return new PageImpl<T>(query.getResultList(), pageable, Long.parseLong(countQuery.getSingleResult().toString()));
	}

	@Override
	public Page<T> queryByExampleWithRange(Example<T> example, List<Range<T>> ranges, Pageable pageable) {
		Specification<T> byExample = new ExampleSpecification<>(example);
        Specification<T> byRanges = new RangeSpecification<>(ranges);
        return findAll(Specification.where(byExample).and(byRanges), pageable);
	}

}
